package MIU.TwistedLabirynth.pac;

import java.io.IOException;
import java.util.Date;
import java.util.Iterator;

import org.anddev.andengine.audio.music.Music;
import org.anddev.andengine.audio.music.MusicFactory;
import org.anddev.andengine.audio.sound.Sound;
import org.anddev.andengine.audio.sound.SoundFactory;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.background.RepeatingSpriteBackground;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.util.Vector2Pool;
import org.anddev.andengine.opengl.font.Font;
import org.anddev.andengine.opengl.font.FontFactory;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.sensor.accelerometer.AccelerometerData;
import org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.Debug;

import MIU.TwistedLabirynth.Levels.LevelController;
import MIU.TwistedLabirynth.db.HighScoreDb;
import MIU.TwistedLabirynth.menu.LevelMenu;
import MIU.TwistedLabirynth.menu.MainMenu;
import MIU.TwistedLabirynth.menu.SettingsMenu;
import android.graphics.Color;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Joint;

public class GameLogicController extends BaseGameActivity implements IAccelerometerListener {
	
	public static final int CAMERA_WIDTH = 460;
	public static final int CAMERA_HEIGHT = 320;
	
	private final MainMenu mainMenu;
	private final LevelMenu levelMenu;
	private final SettingsMenu settingsMenu;
	// private final Scene gameScene;
	private Scene gameScene;
	private PhysicsWorld physicsWorld;
	private Scene mainMenuScene;
	private Scene settingsMenuScene;
	
	private PlayerProfileManager playerProfileManager;
	public LevelController levelController;
	private Camera camera;

	public BitmapTextureAtlas mTexture;
	
	public BitmapTextureAtlas mEnemyTexture;
	public TextureRegion enemyTextureRegion;

	public BitmapTextureAtlas mCarouselTexture;
	public TextureRegion carouselTextureRegion;

	public BitmapTextureAtlas mHoleTexture;
	public TextureRegion mHoleTextureRegion;

	public BitmapTextureAtlas mSwordTexture;
	public TextureRegion mSwordTextureRegion;

	public BitmapTextureAtlas mCannonTexture;
	public TextureRegion mCannonTextureRegion;

	public BitmapTextureAtlas mSpikesTexture;
	public TextureRegion mSpikesTextureRegion;

	public BitmapTextureAtlas mTrampolineTexture;
	public TextureRegion mTrampolineTextureRegion;
	
	public BitmapTextureAtlas mFinishLineTexture;
	public TextureRegion mFinishLineTextureRegion;
	
	public BitmapTextureAtlas mBlockTexture;
	public TextureRegion mBlockTextureRegion;
	
	private float mGravityX;
	private float mGravityY;
	private final Vector2 mTempVector = new Vector2();

	public TiledTextureRegion mCircleFaceTextureRegion;
	
	public BitmapTextureAtlas mDiamantTexture;
	public TextureRegion mDiamantTextureRegion;
	
	private RepeatingSpriteBackground mGrassBackground;
	private RepeatingSpriteBackground mMenuBackground;
	
	public BitmapTextureAtlas mBackgroundTexture;
	public TextureRegion mBackgroundTextureRegion;

	private Sound gameOverSound;
	private Music gameMusic;
	
	public BitmapTextureAtlas mLevelMenuTexture;
	public TextureRegion mLevelTextureRegion;
	
	private long lDateTime = -1;

	private BitmapTextureAtlas fontTexture;
	public Font font;

	private HighScoreDb highscoreDB;

	public GameLogicController() {
		mainMenu = new MainMenu(this);
		levelMenu = new LevelMenu(this);
		settingsMenu = new SettingsMenu(this);
		gameScene = new Scene();
		// physicsWorld = new PhysicsWorld(new Vector2(0,
		// SensorManager.GRAVITY_EARTH), false);
		// gameScene.registerUpdateHandler(physicsWorld);
	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}
	
	@Override
	public Engine onLoadEngine() {
		playerProfileManager = new PlayerProfileManager(this);

		levelController = new LevelController(this);

		camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE,
				new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
		engineOptions.setNeedsSound(true);
		engineOptions.setNeedsMusic(true);

		// turning off VBO
		engineOptions.getRenderOptions().disableExtensionVertexBufferObjects();

		return new Engine(engineOptions);
	}
	
	@Override
	public void onLoadResources() {
		loadMusic();

		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		mainMenu.loadResources();
		levelMenu.loadResources();
		settingsMenu.loadResources();
		levelController.loadResources();

		this.mTexture = new BitmapTextureAtlas(64, 64,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mCircleFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mTexture,
				this, "silver_ball.png", 0, 32, 2, 1); // 64x32
		
		this.mEnemyTexture = new BitmapTextureAtlas(128, 128,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		enemyTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mEnemyTexture, this,
				"ball_enemy.png", 0, 0);
		
		this.mCarouselTexture = new BitmapTextureAtlas(128, 128,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.carouselTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mCarouselTexture,
				this, "carousel.png", 0, 0);
		
		this.mHoleTexture = new BitmapTextureAtlas(32, 32,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mHoleTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mHoleTexture,
				this, "hole.png", 0, 0);
		
		this.mSwordTexture = new BitmapTextureAtlas(32, 128,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mSwordTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mSwordTexture,
				this, "sword.png", 0, 0);

		this.mCannonTexture = new BitmapTextureAtlas(64, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mCannonTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mCannonTexture, this,
				"cannon.png", 0, 0);

		this.mSpikesTexture = new BitmapTextureAtlas(32, 16, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mSpikesTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mSpikesTexture, this,
				"spikes.png", 0, 0);

		this.mTrampolineTexture = new BitmapTextureAtlas(32, 32, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		this.mTrampolineTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mTrampolineTexture, this,
				"Trampoline.png", 0, 0);
		
		this.mDiamantTexture = new BitmapTextureAtlas(32, 32,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		mDiamantTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mDiamantTexture, this,
				"diamant_1.png", 0, 0);
		
		mBackgroundTexture = new BitmapTextureAtlas(128, 128,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		mBackgroundTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBackgroundTexture,
				this, "background_parket_128.png", 0, 0);
		
		this.mBlockTexture = new BitmapTextureAtlas(64, 64,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		mBlockTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBlockTexture, this,
				"block_box1.png", 0, 0);
		
		this.mLevelMenuTexture = new BitmapTextureAtlas(128, 128,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		mLevelTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mLevelMenuTexture, this,
				"button_level_1.png", 0, 0);
		
		this.mFinishLineTexture = new BitmapTextureAtlas(32, 32,
				TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		mFinishLineTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mFinishLineTexture,
				this, "finish_line32.png", 0, 0);
		

		this.mEngine.getTextureManager().loadTextures(this.mTexture,
				this.mEnemyTexture, this.mFinishLineTexture, 
				this.mBlockTexture, this.mDiamantTexture, 
				this.mLevelMenuTexture, this.mBackgroundTexture,
				this.mCarouselTexture, this.mCannonTexture,
				this.mSpikesTexture, this.mTrampolineTexture, 
				this.mSwordTexture, this.mHoleTexture);

		/* Load the font we are going to use. */
		FontFactory.setAssetBasePath("font/");
		fontTexture = new BitmapTextureAtlas(512, 512, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
		font = FontFactory.createFromAsset(fontTexture, this, "Plok.ttf", 24, true, Color.WHITE);

		this.mEngine.getTextureManager().loadTexture(fontTexture);
		this.mEngine.getFontManager().loadFont(font);
	}

	private void loadMusic() {
		SoundFactory.setAssetBasePath("mfx/");
		try {
			this.gameOverSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this,
					"game_over.ogg");
		} catch (final IOException e) {
			Debug.e(e);
		}
		MusicFactory.setAssetBasePath("mfx/");
		try {
			this.gameMusic = MusicFactory.createMusicFromAsset(this.mEngine.getMusicManager(), this,
					"wagner_the_ride_of_the_valkyries.ogg");
			this.gameMusic.setLooping(true);
		} catch (final IOException e) {
			Debug.e(e);
		}

		levelController.setMusic(gameMusic, gameOverSound);
	}

	public Scene newGameLevelScene(int levelId){
		if (physicsWorld != null) {
			physicsWorld.dispose();
		}
		disposeSceneResources(gameScene);
		// this.mPhysicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0,
		// SensorManager.GRAVITY_EARTH), false)
		// disposeGameResources();
		gameScene = new Scene();
		physicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
		//
		gameScene.registerUpdateHandler(physicsWorld);
		levelController.loadLevel(levelId);
		this.enableAccelerometerSensor(this);
		Log.v("gra", "level: " + levelId);
		if (settingsMenu.isMusicEnabled()) {
			gameMusic.setLooping(true);
			gameMusic.resume();
		}

		return gameScene;
	}

	@Override
	public Scene onLoadScene() {
		this.mEngine.registerUpdateHandler(new FPSLogger());

		highscoreDB = new HighScoreDb(this);
		// load static scenes
		mainMenuScene = mainMenu.createMenuScene();
		settingsMenuScene = settingsMenu.createSettingSubMenu();

		return mainMenuScene;
	}

	@Override
	public void onLoadComplete() {
		// TODO Auto-generated method stub

	}
	
	final int con = 10;

	@Override
	public void onAccelerometerChanged(AccelerometerData pAccelerometerData) {
		// this.mGravityX = pAccelerometerData.getX() * 2;
		// this.mGravityY = pAccelerometerData.getY() * 2;
		//
		// if (this.mGravityX > con)
		// this.mGravityX = con;
		// if (this.mGravityY > con)
		// this.mGravityY = con;
		//
		// if (this.mGravityX < con * (-1))
		// this.mGravityX = con * (-1);
		// if (this.mGravityY < con * (-1))
		// this.mGravityY = con * (-1);
		//
		// this.mTempVector.set(this.mGravityX, this.mGravityY);
		// this.mPhysicsWorld.setGravity(this.mTempVector);
		//
		// Log.v("Gravity", "x: " + this.mGravityX + " y: " + this.mGravityY);
		// Log.v("Accelerometer", "x: " + pAccelerometerData.getX() + " y: " +
		// pAccelerometerData.getY());
//		final Vector2 gravity = Vector2Pool.obtain(pAccelerometerData.getX(), pAccelerometerData.getY());
		// this.mPhysicsWorld.setGravity(gravity);
		// Vector2Pool.recycle(new Vector2(this.mGravityX, this.mGravityY));
		// final Vector2 gravity = Vector2Pool.obtain(pAccelerometerData.getX(),
		// pAccelerometerData.getY());
		//
		// Vector2 force = new Vector2(gravity.x, gravity.y);
		//
		// Vector2 point = levelController.getmPlayerBody().getWorldCenter();
		//
		// levelController.getmPlayerBody().applyForce(force, point);
		//
		// Vector2Pool.recycle(gravity);

//		float tempVelocityY = levelController.getmPlayerBody().getLinearVelocity().y + pAccelerometerData.getY() * 10
//				* 100;
//		float tempVelocityX = levelController.getmPlayerBody().getLinearVelocity().x + pAccelerometerData.getX() * 10
//				* 100;
//		if (tempVelocityY > 100)
//			tempVelocityY = 100;
//		if (tempVelocityY < 100)
//			tempVelocityY = -100;
//
//		if (tempVelocityX > 100)
//			tempVelocityX = 100;
//		if (tempVelocityX < 100)
//			tempVelocityX = -100;
//
//		levelController.getmPlayerBody().setLinearVelocity(tempVelocityX, tempVeloc, ityY);
		levelController.getmPlayerBody().setLinearVelocity(pAccelerometerData.getX(), pAccelerometerData.getY()); // directly
		// final Vector2 gravity = Vector2Pool.obtain(pAccelerometerData.getX(),
		// pAccelerometerData.getY());
		// physicsWorld.setGravity(gravity);
		// Vector2Pool.recycle(new Vector2(this.mGravityX, this.mGravityY));

																													// from
																													// accelerometer

	}
	
	public boolean checkTouchTime(){
		
		if(lDateTime == -1)
		{
			lDateTime = new Date().getTime();
			return true;
		}
		
		long lDateCurrentTime = new Date().getTime();
		if(lDateCurrentTime - lDateTime > 500)
		{
			lDateTime = lDateCurrentTime;
			return true;
		}
		return false;
	}
	
	//Scene levelSubMenuPage1;

	@Override
	public boolean onKeyDown(final int pKeyCode, final KeyEvent pEvent) {
		if(pKeyCode == KeyEvent.KEYCODE_BACK && pEvent.getAction() == KeyEvent.ACTION_DOWN) {
			this.mEngine.setScene(mainMenu.createMenuScene());
			if (gameMusic.isPlaying()) {
				gameMusic.pause();
			}
			return true;
		} 
		if(pKeyCode == KeyEvent.KEYCODE_DPAD_CENTER && pEvent.getAction() == KeyEvent.ACTION_DOWN) {
			this.mEngine.setScene(mainMenu.createMenuScene());
			if (gameMusic.isPlaying()) {
				gameMusic.pause();
			}
			return true;
		} 
		else {
			return super.onKeyDown(pKeyCode, pEvent);
		}
	}

	public MainMenu getMainMenu() {
		return mainMenu;
	}

	public PlayerProfileManager getPlayerProfileManager() {
		return playerProfileManager;
	}

	public LevelMenu getLevelMenu() {
		return levelMenu;
	}

	public SettingsMenu getSettingsMenu() {
		return settingsMenu;
	}

	public Scene getScene() {
		return gameScene;
	}

	public PhysicsWorld getPhysicsWorld() {
		return physicsWorld;
	}

	public void disposeGameResources() {
		for (Iterator<Body> allBodies = physicsWorld.getBodies(); allBodies.hasNext();) {
			final Body currentBody = allBodies.next();
				this.runOnUpdateThread(new Runnable() {
					@Override
					public void run() {
						physicsWorld.destroyBody(currentBody);
					}
				});
		}
		for (Iterator<Joint> allJoints = physicsWorld.getJoints(); allJoints.hasNext();) {
			final Joint currentJoint = allJoints.next();
				this.runOnUpdateThread(new Runnable() {
					@Override
					public void run() {
					physicsWorld.destroyJoint(currentJoint);
					}

				});

		}
		// disposeSceneResources(gameScene);
		physicsWorld.clearForces();
		physicsWorld.dispose();
		// physicsWorld.reset();
		// mEngine.getFontManager().clear();

	}

	public void disposeSceneResources(final Scene scene) {
		scene.clearEntityModifiers();
		scene.reset();
		scene.clearTouchAreas();
		scene.clearUpdateHandlers();
		runOnUpdateThread(new Runnable() {
			@Override
			public void run() {
				scene.clearChildScene();
				scene.detachSelf();
				scene.detachChildren();
			}
		});
	}

	public void setLevelMenuScene() {
		mEngine.setScene(levelMenu.createLevelSubmenu());
	}

	public void setSettingsMenuScene() {
		mEngine.setScene(settingsMenuScene);
	}

	public HighScoreDb getHighscoreDB() {
		return highscoreDB;
	}
}
